package edu.tfh.s2.ehkbot.steuerung;

import java.util.Vector;

import edu.tfh.s2.ehkbot.EHKBotMain;
import edu.tfh.s2.ehkbot.daten.Protokoll;
import edu.tfh.s2.ehkbot.gerete.sensoren.simulation.SensorStorryGreife;
import edu.tfh.s2.ehkbot.inventar.Einkaufsauftrag;
import edu.tfh.s2.ehkbot.inventar.Einkaufsposten;
import edu.tfh.s2.ehkbot.inventar.Regalfach;
import edu.tfh.s2.ehkbot.inventar.Ware;
import edu.tfh.s2.ehkbot.inventar.Warenbestand;
import edu.tfh.s2.ehkbot.inventar.Warenbox;
import edu.tfh.s2.ehkbot.inventar.WarenboxRegal;
import edu.tfh.s2.ehkbot.inventar.Einkaufsauftrag.EinkaufsauftragStatus;
import edu.tfh.s2.ehkbot.inventar.Einkaufsposten.EinkaufspostenStatus;
import edu.tfh.s2.ehkbot.inventar.Regalfach.RegalfachException;
import edu.tfh.s2.ehkbot.inventar.WarenboxRegal.KeinFreiesFach;
import edu.tfh.s2.ehkbot.simulation.TerminalGUI;
import edu.tfh.s2.ehkbot.steuerung.EHKBotNavigieren.KeinWegGefunden;
import edu.tfh.s2.ehkbot.steuerung.ObjektGreifen.GreifenNichtMoeglich;

/**
 * Die Klasse EinkaufsAuftragAusfuehren arbeitet einen Einkaufsauftrag ab.
 * 
 * @author s2zehn
 */
public class EinkaufsAuftragAusfuehren {
	/**
	 * Wird geworfen wenn ein Warenbox Problem auftaucht.
	 */
	public static class WarenBoxProblem extends Exception {
		private static final long serialVersionUID = 1L;
	}

	/**
	 * Wird geworfen wenn ein Waren Problem auftaucht.
	 */
	public static class WarenProblem extends Exception {
		private static final long serialVersionUID = 1L;
	}

	private ObjektGreifen objektGreifen = new ObjektGreifen();

	/**
	 * Arbeitet einen Einkaufsauftrag ab.
	 * 
	 * @param einkaufsauftrag
	 *            Der Auftrag.
	 */
	public void fuehreEinkaufsAuftragAus(Einkaufsauftrag einkaufsauftrag) {

		SensorStorryGreife ssg = new SensorStorryGreife();
		ssg.setSubject(EHKBotMain.getInstance().getEHKBot().getGreifarm().getGreifer());
		EHKBotMain.getInstance().getEHKBot().getGreifarm().getGreifer().attach(ssg);

		try {
			ladeWarenboxAuf(einkaufsauftrag.getWarenbox());
		} catch (WarenBoxProblem e) {
			Protokoll.getInstanc().exception(e);
			einkaufsauftrag.setStatus(EinkaufsauftragStatus.NICHTMOEGLICH);
			return;
		}

		Vector<Einkaufsposten> posten = einkaufsauftrag.getEinkaufsposten();
		Warenbestand warenbestand = EHKBotMain.getInstance().getGeschaeft().getWarenbestand();

		for (Einkaufsposten einPosten : posten) {
			Ware ware = einPosten.getWare();
			try {
				new EHKBotNavigieren().navigiereZumZiel(ware.getPosition());
				for (int i = 0; i < einPosten.getMenge(); ++i) {
					if (warenbestand.menge(ware) == 0)
						throw new WarenProblem();
					ladeWareInGreifer(ware);
					warenbestand.setMenge(ware, warenbestand.menge(ware) - 1);
					legeWareAb();
					einkaufsauftrag.getWarenbox().addWare(ware);
					einPosten.setStatus(EinkaufspostenStatus.TEILWEISE);
				}
				einPosten.setStatus(EinkaufspostenStatus.ERLAEDIGT);
			} catch (Exception e) {
				Protokoll.getInstanc().exception(e);
				einPosten.setStatus(EinkaufspostenStatus.NICHTMOEGLICH);

				Protokoll.getInstanc().exception(e);
				Protokoll.getInstanc().fehler(
					"EinkaufsAuftragAusfuehren",
					String.format(
						"Konnte ware mit den Barcode %d nicht einladen.",
						einPosten.getWare().getBarcode()),
					3);
			}
			TerminalGUI.getInstance().refresh(einkaufsauftrag);
		}

		try {
			ladeWarenboxAb(einkaufsauftrag.getWarenbox());
		} catch (KeinWegGefunden e) {
			Protokoll.getInstanc().exception(e);
		} catch (RegalfachException e) {
			Protokoll.getInstanc().exception(e);
		} catch (KeinFreiesFach e) {
			Protokoll.getInstanc().exception(e);
		}

	}

	/**
	 * Kümmert sich um das Handling der Ware, bis es in den Greifer ist.
	 * 
	 * @param ware
	 *            Die zu greifende Ware.
	 * @throws WarenProblem
	 *             Wenn ein Problem mit der Ware aufgetaucht ist.
	 * @throws GreifenNichtMoeglich
	 *             Wenn das Greifen nicht möglich ist.
	 */
	public void ladeWareInGreifer(Ware ware) throws WarenProblem, GreifenNichtMoeglich {
		objektGreifen.greifeWare(ware);
	}

	/**
	 * Packt die Warenbox ins Regalfach.
	 * 
	 * @param warenbox
	 *            Die Warenbox.
	 * @throws KeinWegGefunden
	 *             Wenn kein Weg gefunden wurde.
	 * @throws RegalfachException
	 *             Wenn ein Problem beim Regalfach auftrit.
	 * @throws KeinFreiesFach
	 *             Wenn kein freies Fach gefunden wird.
	 */
	public void ladeWarenboxAb(Warenbox warenbox) throws KeinWegGefunden, RegalfachException, KeinFreiesFach {
		WarenboxRegal regal = EHKBotMain.getInstance().getGeschaeft().getWarenboxregal();
		Regalfach fach = regal.sucheLeeresRegalfach();
		new EHKBotNavigieren().navigiereZumZiel(fach.getPosition());
		fach.belege(warenbox);
		objektGreifen.ladeWarenBoxAb(fach);
	}

	/**
	 * Kümmert sich um das Handling der Warenbox.
	 * 
	 * @param warenbox
	 *            Die Warenbox die geladen werden soll.
	 * @throws WarenBoxProblem
	 *             Wenn es ein Problem beim laden gibt.
	 */
	public void ladeWarenboxAuf(Warenbox warenbox) throws WarenBoxProblem {
		Regalfach regalfach = EHKBotMain.getInstance().getGeschaeft().getWarenboxregal().sucheWarenboxRegalfachZuWarenbox(
			warenbox);
		try {
			new EHKBotNavigieren().navigiereZumZiel(regalfach.getPosition());
			regalfach.befreie();
			objektGreifen.ladeWarenboxAuf(regalfach);
		} catch (KeinWegGefunden e) {
			Protokoll.getInstanc().exception(e);
		}

	}

	/**
	 * Legt die Ware die sich im Greifer befindet ab.
	 */
	public void legeWareAb() {
		objektGreifen.legeWareAb();
	}
}
